package org.ssm.learn;

/**
 * Description: 当flag=true的时候备份 A 数据库
 * 当flag=false的时候备份 B数据库 以此实现交叉备份
 */
public class TaskBackup {
    volatile private boolean flag = false;// 采用volatile关键字，使变量于多个线程之间可见

    synchronized public void backupA() { // synchronized 关键字，避免多个线程对同一对象的修改，导致“脏读”
        try {
            // 记住，这里的判断一定要用while 而不是用if，为什么呢？因为存在多个线程，不止备份B数据库的线程在等待，可能备份A数据库的线程也在等待，如果用if
            // 可能会导致 同类唤醒同类的 情况导致线程的“假死”。
            while (flag == false) {
                this.wait();
            }
            System.out.println(Thread.currentThread().getName() + "正在备份 A 数据库！");// 模拟备份数据库
            flag = false;
            this.notifyAll();// 唤醒所有等待的线程，当然这里并不会唤醒backupA 的线程，原因在于，backupA的线程这个时候又做了一个while判断，导致线程继续在等待了，而只有backupB的线程被唤醒了
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    synchronized public void backupB() {
        try {
            while (flag == true) {
                this.wait();
            }
            System.out.println(Thread.currentThread().getName() + "正在备份 B 数据库！");// 模拟备份数据库
            flag = true;
            this.notifyAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}